/*******************************************************************************
 * (c) Copyright 2017 lvxi. All Rights Reserved.
 ******************************************************************************/

package edu.jxufe.nb112.common.code.codedc;

/**
 * Created by lvxi on 2017/4/16.
 * Note:
 */

import edu.jxufe.nb112.common.code.exception.CommonCodeException;
import org.apache.commons.text.RandomStringGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.SecureRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 DES加密介绍
 DES是一种对称加密算法，所谓对称加密算法即：加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究，
 后来被美国政府正式采用，之后开始广泛流传，但是近些年使用越来越少，因为DES使用56位密钥，以现代计算能力，
 24小时内即可被破解。虽然如此，在某些简单应用中，我们还是可以使用DES加密算法，本文简单讲解DES的JAVA实现
 。
 注意：DES加密和解密过程中，密钥长度都必须是8的倍数
 */
public class DESUtils {
    private static final Logger LOG = LoggerFactory.getLogger(DESUtils.class.getName());
    private  final static Pattern timePattern = Pattern.compile("(?<=^\\[)[\\d\\|]*(?=\\])");
    private final static String password;
    static {
        //生成默认随机密码
        RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
        password = generator.generate(16);
        if(LOG.isDebugEnabled()){
            LOG.debug("DESUtils随机秘钥:{}",password);
        }
    }

    /**
     * 使用默认随机密码加密
     * @param in
     * @return
     */
    public static  String encode(String in){
        return encode(in,password);
    }
    /**
     * 加密
     * @param in String
     * @param password String
     * @return
     */
    public static  String encode(String in, String password) {
        String hex="";
        try{
            byte[] bytIn = in.getBytes();
            SecureRandom random = new SecureRandom();
            DESKeySpec desKey = new DESKeySpec(password.getBytes());
            //创建一个密匙工厂，然后用它把DESKeySpec转换成
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(desKey);
            //Cipher对象实际完成加密操作
            Cipher cipher = Cipher.getInstance("DES");
            //用密匙初始化Cipher对象
            cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
            //现在，获取数据并加密
            //正式执行加密操作
            byte[] byIn = cipher.doFinal(bytIn);
            hex = HexUtils.byte2hexString(byIn);
        }catch(Exception e){
            LOG.error("DES加密错误",e);
            throw  new CommonCodeException("DES加密错误",e);
        }
        return hex;
    }
    /**
     * 解密
     * @param hex String
     * @param password String
     * @return String
     * @throws Exception
     */
    public static String decode(String hex, String password){
        String out="";
        try {
            // DES算法要求有一个可信任的随机数源
            SecureRandom random = new SecureRandom();
            // 创建一个DESKeySpec对象
            DESKeySpec  desKey = new DESKeySpec(password.getBytes());
            // 创建一个密匙工厂
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            // 将DESKeySpec对象转换成SecretKey对象
            SecretKey securekey = keyFactory.generateSecret(desKey);
            // Cipher对象实际完成解密操作
            Cipher cipher = Cipher.getInstance("DES");
            // 用密匙初始化Cipher对象
            cipher.init(Cipher.DECRYPT_MODE, securekey, random);
            // 真正开始解密操作
            byte[] byOut = cipher.doFinal( HexUtils.hex2Byte(hex));
            out = new String(byOut,"utf-8");
        } catch (Exception e) {
            LOG.error("DES加密错误",e);
            throw  new CommonCodeException("DES加密错误",e);
        }
        return out;
    }

    /**
     * 带时间戳加密,在liveTime毫秒后失效
     * @param in
     * @param liveTime 有效时间 毫秒
     * @return
     */
    public static String encodeTimestap(String in, long liveTime) {
        return encodeTimestap(in, liveTime, password);
    }
    /**
     * 带时间戳加密,在liveTime毫秒后失效
     * @param in
     * @param liveTime 有效时间 毫秒
     * @param password
     * @return
     */
    public static  String encodeTimestap(String in, long liveTime , String password){
        String timeInfo = System.currentTimeMillis()+"|"+liveTime;
        in = "["+timeInfo+"]"+in;
        return encode(in,password);
    }

    /**
     * 带时间戳解密
     * @param hex
     * @return
     */
    public static String decodeTimestap(String hex){
        return decodeTimestap(hex,password);
    }
    /**
     * 带时间戳解密
     * @param hex
     * @param password
     * @return
     */
    public static String decodeTimestap(String hex, String password){
        String inStr = decode(hex,password);
        Matcher matcher = timePattern.matcher(inStr);
        if(matcher.find()){
            String detimeStr = matcher.group();
            String[] destime = detimeStr.split("\\|");
            long time = Long.parseLong(destime[0]);
            long liveTime = Long.parseLong(destime[1]);
            if(System.currentTimeMillis()-time <= liveTime){
                return inStr.substring(detimeStr.length()+2);
            }
        }
        return null;
    }

}
